package com.csx.data.routing.sample.utils;

import com.csx.data.routing.sample.entity.MonthBillEntity;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class TableTimeUtils {

    // formatter：负责将一个日期处理成 YYYYMM 格式
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMM");

    private static final DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    // 表的前缀
    private static final String tablePrefix = "month_bills_";

    // 将一个日期格式化为YYYYMM格式
    public static String getYearMonth(Date date) {
        LocalDateTime localDateTime = date
                .toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
        return localDateTime.format(formatter);
    }

    // 获取目标数据的表名（操作单条数据公用的方法：增删改查）
    public static void getDataByTable(MonthBillEntity monthBills){
        // 获取传入对象的时间
        Date billDate = monthBills.getBillDate();
        // 根据该对象中的时间，计算出要操作的表名后缀
        String yearMonth = getYearMonth(billDate);
        // 将表前缀和后缀拼接，得到完整的表名，如：month_bills_202211
        monthBills.setTargetTable(tablePrefix + yearMonth);
    }

    // 根据流水号得到表名
    public static void getTableBySerialNumber(MonthBillEntity monthBills){
        // 获取流水号的后13位（时间戳）
        String timeMillis = monthBills.getSerialNumber().
                substring(monthBills.getSerialNumber().length() - 13);
        // 将字符串类型的时间戳转换为long类型
        long millis = Long.parseLong(timeMillis);
        // 调用getYearMonth()方法获取时间戳中的年月
        String yearMonth = getYearMonth(new Date(millis));
        // 用表的前缀名拼接年月，得到最终要操作的表名
        monthBills.setTargetTable(tablePrefix + yearMonth);
    }

    // 根据日期生成SQL语句的方法
    public static String getRangeQuerySQL(String startTime, String endTime){
        // 先获取两个日期之间的所有表名
        List<String> tables = getRangeQueryByTables(startTime, endTime);
        // 提前创建一个字符串对象保存SQL语句
        StringBuilder sql = new StringBuilder();
        // 如果查询的两个日期是同一张表，则直接生成 BETWEEN AND 的SQL语句
        if (tables.size() == 1){
            sql.append("select * from ")
                    .append(tables.get(0))
                    .append(" where bill_date BETWEEN '")
                    .append(startTime)
                    .append("' AND '")
                    .append(endTime)
                    .append("';");
            // 如果本次范围查询的两个日期之间有多张表
        }else {
            // 则用for循环遍历所有表名
            for (String table : tables) {
                // 对于第一张表则只需要查询开始日期之后的数据
                if (table.equals(tables.get(0))){
                    sql.append("select * from ")
                            .append(table)
                            .append(" where bill_date > '")
                            .append(startTime)
                            .append("' union all ");
                }
                // 对于最后一张表只需要查询结束日期之前的数据
                else if (table.equals(tables.get(tables.size()-1))){
                    sql.append("select * from ")
                            .append(table)
                            .append(" where bill_date < '")
                            .append(endTime)
                            .append("';");
                    // 对于其他表则获取所有数据
                } else {
                    sql.append("select * from ")
                            .append(table)
                            .append("' union all ");
                }
            }
        }
        // 返回最终生成的SQL语句
        return sql.toString();
    }

    // 获取按时间范围查询时，两个日期之间，所有月份账单表的表名
    private static List<String> getRangeQueryByTables(String startTime, String endTime){

        // 声明保存表名的集合
        List<String> tables = new ArrayList<>();
        // 将两个传入的字符日期转换成日期类型
        Date startDate = Date.from(LocalDate.parse(startTime, formatter2).atStartOfDay(ZoneId.systemDefault()).toInstant());
        Date endDate = Date.from(LocalDate.parse(endTime, formatter2).atStartOfDay(ZoneId.systemDefault()).toInstant());
        //用 Calendar 进行日期比较判断
        Calendar calendar = Calendar.getInstance();
        while (startDate.getTime() <= endDate.getTime()){
            LocalDateTime localDateTime = startDate
                    .toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime();
            // 把生成的月份拼接表前缀名，加入到集合中
            tables.add(tablePrefix + localDateTime.format(formatter));
            // 设置日期，并把比对器的日期增加一月
            calendar.setTime(startDate);
            calendar.add(Calendar.MONTH, 1);
            // 获取增加后的日期
            startDate = calendar.getTime();
        }
        // 返回两个日期之间的所有表名
        return tables;
    }





}
